package com.vincent.suchao.lcld;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
import android.widget.Scroller;

public class MySlide extends ViewGroup {
	private int screen_width;
	private SlideListener sListener;
	private Scroller mScroller;
	private VelocityTracker mVelocityTracker;

	private int mScrollX = 0;
	private int mCurrentScreen = 0;

	private float mLastMotionX;

	private static final String LOG_TAG = "DragableSpace";

	private static final int SNAP_VELOCITY = 600;

	private final static int TOUCH_STATE_REST = 0;
	private final static int TOUCH_STATE_SCROLLING = 1;

	private int mTouchState = TOUCH_STATE_REST;

	private int mTouchSlop = 0;

	public MySlide(Context context) {
		super(context);
		mScroller = new Scroller(context);

		mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

		this.setLayoutParams(new ViewGroup.LayoutParams(
				ViewGroup.LayoutParams.FILL_PARENT,
				ViewGroup.LayoutParams.FILL_PARENT));
	}

	public MySlide(Context context, AttributeSet attrs) {
		super(context, attrs);
		mScrollInterpolator = new WorkspaceOvershootInterpolator();
		mScroller = new Scroller(context, mScrollInterpolator);

		mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

		this.setLayoutParams(new ViewGroup.LayoutParams(
				ViewGroup.LayoutParams.FILL_PARENT,
				ViewGroup.LayoutParams.FILL_PARENT));

		TypedArray a = getContext().obtainStyledAttributes(attrs,
				R.styleable.DragableSpace);
		mCurrentScreen = a.getInteger(R.styleable.DragableSpace_default_screen,
				0);
		a.recycle();
		final ViewConfiguration configuration = ViewConfiguration
				.get(getContext());
		mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
	}

	public int getScreen_width() {
		return screen_width;
	}

	public void setScreen_width(int screenWidth) {
		screen_width = screenWidth;
	}

	public void setsListener(SlideListener sListener) {
		this.sListener = sListener;
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		/*
		 * This method JUST determines whether we want to intercept the motion.
		 * If we return true, onTouchEvent will be called and we do the actual
		 * scrolling there.
		 */

		/*
		 * Shortcut the most recurring case: the user is in the dragging state
		 * and he is moving his finger. We want to intercept this motion.
		 */
		int action = ev.getAction();
		// System.out.println(action +
		// " onInterceptTouchEvent   @@@@@@@@@@@@@ ");
		if ((action == MotionEvent.ACTION_MOVE)
				&& (mTouchState != TOUCH_STATE_REST)) {

			return true;
		}

		if (mVelocityTracker == null) {
			mVelocityTracker = VelocityTracker.obtain();
		}
		mVelocityTracker.addMovement(ev);

		final float x = ev.getX();

		switch (action & MotionEvent.ACTION_MASK) {
		case MotionEvent.ACTION_MOVE:
			// sListener.onSlide(true);
			/*
			 * mIsBeingDragged == false, otherwise the shortcut would have
			 * caught it. Check whether the user has moved far enough from his
			 * original down touch.
			 */

			/*
			 * Locally do absolute value. mLastMotionX is set to the y value of
			 * the down event.
			 */

			final int xDiff = (int) Math.abs(x - mLastMotionX);

			boolean xMoved = xDiff > mTouchSlop;

			if (xMoved) {
				// Scroll if the user moved far enough along the X axis
				mTouchX = mScrollX;
				mTouchState = TOUCH_STATE_SCROLLING;
				mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
				// setChildrenDrawnWithCacheEnabled(true);
				// setChildrenDrawingCacheEnabled(true);
			}
			break;

		case MotionEvent.ACTION_DOWN:
			// Remember location of down touch
			mLastMotionX = x;

			/*
			 * If being flinged and user touches the screen, initiate drag;
			 * otherwise don't. mScroller.isFinished should be false when being
			 * flinged.
			 */
			mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST
					: TOUCH_STATE_SCROLLING;

			break;

		case MotionEvent.ACTION_CANCEL:
		case MotionEvent.ACTION_UP:
			// Release the drag
			// sListener.onSlide(false);
			mTouchState = TOUCH_STATE_REST;
			// setChildrenDrawnWithCacheEnabled(false);
			break;
		}

		/*
		 * The only time we want to intercept motion events is if we are in the
		 * drag mode.
		 */

		return mTouchState != TOUCH_STATE_REST;
	}

	boolean isBouncing = true;

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		/*
		 * if (!mScroller.isFinished()) { // mScroller.abortAnimation(); return
		 * false; // We don't want the events. Let them fall through to the all
		 * apps // view. }
		 */

		if (mVelocityTracker == null) {
			mVelocityTracker = VelocityTracker.obtain();
		}
		mVelocityTracker.addMovement(event);

		final int action = event.getAction();
		// System.out.println(action + " onTouchEvent   @@@@@@@@@@@@@ ");
		final float x = event.getX();

		if (mVelocityTracker == null) {
			mVelocityTracker = VelocityTracker.obtain();
		}
		mVelocityTracker.addMovement(event);

		switch (action) {
		case MotionEvent.ACTION_DOWN:
			/*
			 * If being flinged and user touches, stop the fling. isFinished
			 * will be false if being flinged.
			 */
			if (!mScroller.isFinished()) {
				mScroller.abortAnimation();
			}

			// Remember where the motion event started
			mLastMotionX = x;

			// setChildrenDrawnWithCacheEnabled(true);
			// setChildrenDrawingCacheEnabled(true);
			break;
		case MotionEvent.ACTION_MOVE:
			// sListener.onSlide(true);
			mTouchState = TOUCH_STATE_SCROLLING;
			// Log.i(LOG_TAG,"event : move");

			// Scroll to follow the motion event
			int deltaX = (int) (mLastMotionX - x);
			mLastMotionX = x;
			// setChildrenDrawnWithCacheEnabled(true);
			// setChildrenDrawingCacheEnabled(true);

			if (deltaX < 0) {
				if (mScrollX > 0) {
					mTouchX += Math.max(-mTouchX, deltaX);
					// scrollBy(Math.max(-mScrollX, deltaX), 0);
					mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
					invalidate();
				}
				if (isBouncing && mCurrentScreen == 0) {
					leftBouncing();
					isBouncing = false;
				}
			} else if (deltaX > 0) {
				if (isBouncing && mCurrentScreen == getChildCount() - 1) {
					rightBouncing();
					isBouncing = false;
				}
				View viewTemp = getChildAt(getChildCount() - 1);
				if (viewTemp == null)
					break;
				final float availableToScroll = viewTemp.getRight() - mTouchX
						- screen_width;
				if (availableToScroll > 0) {
					mTouchX += Math.min(availableToScroll, deltaX);
					mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
					// scrollBy(Math.min((int)availableToScroll, deltaX), 0);
					invalidate();
				}
			} else {
				awakenScrollBars();
			}

			break;
		case MotionEvent.ACTION_UP:
			// sListener.onSlide(false);
			if (mTouchState == TOUCH_STATE_SCROLLING) {
				final VelocityTracker velocityTracker = mVelocityTracker;
				velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);

				int velocityY = (int) velocityTracker.getYVelocity();

				int velocityX = (int) velocityTracker.getXVelocity();

				// System.out.println("velocityX " + velocityX + ", velocityY "
				// + velocityY);

				if (velocityX < 200 && velocityX > -200 && velocityY > 1000) {
					// if (sListener != null)
					// sListener.onQuit();
				}

				if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {
					// Fling hard enough to move left
					snapToScreen(mCurrentScreen - 1, velocityX, true);
					// snapToDestination();
				} else if (velocityX < -SNAP_VELOCITY
						&& mCurrentScreen < getChildCount() - 1) {
					// Fling hard enough to move right
					snapToScreen(mCurrentScreen + 1, velocityX, true);
					// snapToDestination();
				} else {
					snapToDestination();
					isBouncing = true;
				}

				// setChildrenDrawnWithCacheEnabled(false);

				if (mVelocityTracker != null) {
					mVelocityTracker.recycle();
					mVelocityTracker = null;
				}
			}
			mTouchState = TOUCH_STATE_REST;
			break;
		case MotionEvent.ACTION_CANCEL:
			// setChildrenDrawnWithCacheEnabled(false);
			mTouchState = TOUCH_STATE_REST;
			break;
		}
		// mScrollX = this.getScrollX();

		return true;
	}

	private void snapToDestination() {
		final int screenWidth = screen_width;
		if (screenWidth == 0)
			return;
		final int whichScreen = (mScrollX + (screenWidth / 2)) / screenWidth;
		snapToScreen(whichScreen, 0, true);
	}

	public void rightBouncing() {

		int delta = 200;
		mScroller.startScroll(mScrollX, 0, delta, 0, Math.abs(delta) * 2);
		invalidate();

	}

	public void leftBouncing() {

		int delta = -200;
		mScroller.startScroll(mScrollX, 0, delta, 0, Math.abs(delta) * 2);
		invalidate();

	}

	public void snapToScreen(int whichScreen, int velocity, boolean settle) {
		mCurrentScreen = whichScreen;
		View focusedChild = getFocusedChild();
		if (focusedChild != null && whichScreen != mCurrentScreen
				&& focusedChild == getChildAt(mCurrentScreen)) {
			focusedChild.clearFocus();
		}

		final int newX = whichScreen * screen_width;
		final int delta = newX - mScrollX;
		final int screenDelta = Math.max(1,
				Math.abs(whichScreen - mCurrentScreen));
		int duration = (screenDelta + 1) * 100;
		if (!mScroller.isFinished()) {
			mScroller.abortAnimation();
		}

		if (settle) {
			mScrollInterpolator.setDistance(screenDelta);
		} else {
			mScrollInterpolator.disableSettle();
		}

		velocity = Math.abs(velocity);
		if (velocity > 0) {
			duration += (duration / (velocity / BASELINE_FLING_VELOCITY))
					* FLING_VELOCITY_INFLUENCE;
		} else {
			duration += 100;
		}

		awakenScrollBars(duration);

		mScroller.startScroll(mScrollX, 0, delta, 0, duration);
		invalidate();
		if (sListener != null)
			sListener.onComplete(whichScreen);
	}

	public void setToScreen(int whichScreen) {
		mCurrentScreen = whichScreen;
		final int newX = whichScreen * screen_width;
		mScroller.startScroll(newX, 0, 0, 0, 10);
		invalidate();
		if (sListener != null)
			sListener.onComplete(whichScreen);
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		int childLeft = 0;

		final int count = getChildCount();
		for (int i = 0; i < count; i++) {
			final View child = getChildAt(i);
			if (child.getVisibility() != View.GONE) {
				final int childWidth = child.getMeasuredWidth();
				child.layout(childLeft, 0, childLeft + childWidth,
						child.getMeasuredHeight());
				childLeft += childWidth;
			}
		}

	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);

		final int width = MeasureSpec.getSize(widthMeasureSpec);
		final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
		if (widthMode != MeasureSpec.EXACTLY) {
			throw new IllegalStateException("error mode.");
		}

		final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
		if (heightMode != MeasureSpec.EXACTLY) {
			throw new IllegalStateException("error mode.");
		}

		// The children are given the same width and height as the workspace
		final int count = getChildCount();
		for (int i = 0; i < count; i++) {
			getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
		}
		scrollTo(mCurrentScreen * width, 0);
	}

	@Override
	public void computeScroll() {
		// System.out.println((mTouchState)+"   !!!   "+mScroller.computeScrollOffset());
		if (mScroller.computeScrollOffset()) {
			mTouchX = mScrollX = mScroller.getCurrX();
			mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
			scrollTo(mScrollX, 0);
			// Log.i(LOG_TAG, "computeScroll " + mScrollX);
			postInvalidate();
		} else if (mTouchState == TOUCH_STATE_SCROLLING) {
			final float now = System.nanoTime() / NANOTIME_DIV;
			final float e = (float) Math.exp((now - mSmoothingTime)
					/ SMOOTHING_CONSTANT);
			final float dx = mTouchX - mScrollX;
			mScrollX += dx * e;
			mSmoothingTime = now;
			scrollTo(mScrollX, 0);
			// Keep generating points as long as we're more than 1px away from
			// the target
			if (dx > 1.f || dx < -1.f) {

				postInvalidate();
			}

		}
	}

	private WorkspaceOvershootInterpolator mScrollInterpolator;

	private static class WorkspaceOvershootInterpolator implements Interpolator {
		private static final float DEFAULT_TENSION = 0.3f;
		private float mTension;

		public WorkspaceOvershootInterpolator() {
			mTension = DEFAULT_TENSION;
		}

		public void setDistance(int distance) {
			mTension = distance > 0 ? DEFAULT_TENSION / distance
					: DEFAULT_TENSION;
		}

		public void disableSettle() {
			mTension = 0.f;
		}

		public float getInterpolation(float t) {
			// _o(t) = t * t * ((tension + 1) * t + tension)
			// o(t) = _o(t - 1) + 1
			t -= 1.0f;
			return t * t * ((mTension + 1) * t + mTension) + 1.0f;
		}
	}

	// @Override
	// protected void dispatchDraw(Canvas canvas) {
	// // if (MainActivity.isDestroy)
	// // return;
	// boolean restore = false;
	// int restoreCount = 0;
	//
	// // ViewGroup.dispatchDraw() supports many features we don't need:
	// // clip to padding, layout animation, animation listener, disappearing
	// // children, etc. The following implementation attempts to fast-track
	// // the drawing dispatch by drawing only what we know needs to be drawn.
	//
	// boolean fastDraw = mTouchState != TOUCH_STATE_SCROLLING;
	// // If we are not scrolling or flinging, draw only the current screen
	// if (fastDraw) {
	// View view = getChildAt(mCurrentScreen);
	// if (view == null)
	// return;
	// drawChild(canvas, view, getDrawingTime());
	// } else {
	// final long drawingTime = getDrawingTime();
	// final float scrollPos = (float) mScrollX / getWidth();
	// final int leftScreen = (int) scrollPos;
	// final int rightScreen = leftScreen + 1;
	// if (leftScreen >= 0) {
	// View view = getChildAt(leftScreen);
	// if (view == null)
	// return;
	// drawChild(canvas, getChildAt(leftScreen), drawingTime);
	// }
	// if (scrollPos != leftScreen && rightScreen < getChildCount()) {
	// View view = getChildAt(rightScreen);
	// if (view == null)
	// return;
	// drawChild(canvas, getChildAt(rightScreen), drawingTime);
	// }
	// }
	//
	// if (restore) {
	// canvas.restoreToCount(restoreCount);
	// }
	//
	// }

	@Override
	public void scrollTo(int x, int y) {
		super.scrollTo(x, y);
		mTouchX = x;
		mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
	}

	private int mMaximumVelocity;
	private static final float BASELINE_FLING_VELOCITY = 2500.f;
	private static final float FLING_VELOCITY_INFLUENCE = 0.8f;
	private float mTouchX;
	private float mSmoothingTime;
	private static final float SMOOTHING_SPEED = 1.00f;
	private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math
			.log(SMOOTHING_SPEED));
	private static final float NANOTIME_DIV = 1000000000.0f;

	public interface SlideListener {
		public void onComplete(int index);

		// public void onQuit();
		// public void onSlide(boolean isMove);
	}
}

/*
 * package com.fugoo.ew.timeweather.view;
 * 
 * import java.util.ArrayList; import java.util.HashSet;
 * 
 * 
 * import com.fugoo.ew.timeweather.view.MainActivity.SlideListener;
 * 
 * import android.app.WallpaperManager; import
 * android.appwidget.AppWidgetManager; import
 * android.appwidget.AppWidgetProviderInfo; import
 * android.content.ComponentName; import android.content.Context; import
 * android.content.Intent; import android.net.Uri; import android.os.IBinder;
 * import android.os.Parcel; import android.os.Parcelable; import
 * android.util.Log; import android.content.pm.PackageManager; import
 * android.content.pm.ProviderInfo; import android.content.res.TypedArray;
 * import android.graphics.Canvas; import android.graphics.Rect; import
 * android.graphics.drawable.Drawable; import android.util.AttributeSet; import
 * android.view.Display; import android.view.MotionEvent; import
 * android.view.VelocityTracker; import android.view.View; import
 * android.view.ViewGroup; import android.view.ViewConfiguration; import
 * android.view.ViewParent; import android.view.WindowManager; import
 * android.view.View.BaseSavedState; import android.view.View.MeasureSpec;
 * import android.view.View.OnLongClickListener; import
 * android.view.ViewGroup.LayoutParams; import
 * android.view.animation.Interpolator; import android.widget.Scroller; import
 * android.widget.TextView;
 * 
 * 
 * public class MySlide extends ViewGroup { private int mScrollX = 0;
 * 
 * private int screen_width; private SlideListener sListener;
 * 
 * private static final String TAG = "Launcher.Workspace"; private static final
 * int INVALID_SCREEN = -1;
 *//**
 * The velocity at which a fling gesture will cause us to snap to the next
 * screen
 */
/*
 * private static final int SNAP_VELOCITY = 1000; private int mDefaultScreen;
 * private boolean mFirstLayout = true; private int mCurrentScreen; private int
 * mNextScreen = INVALID_SCREEN; private Scroller mScroller; private
 * VelocityTracker mVelocityTracker;
 *//**
 * Target drop area calculated during last acceptDrop call.
 */
/*
 * 
 * private float mLastMotionX; private float mLastMotionY;
 * 
 * private final static int TOUCH_STATE_REST = 0; private final static int
 * TOUCH_STATE_SCROLLING = 1;
 * 
 * private int mTouchState = TOUCH_STATE_REST;
 * 
 * 
 * 
 * private int mTouchSlop; private int mMaximumVelocity;
 * 
 * private static final int INVALID_POINTER = -1;
 * 
 * private int mActivePointerId = INVALID_POINTER;
 * 
 * 
 * 
 * private static final float NANOTIME_DIV = 1000000000.0f; private static final
 * float SMOOTHING_SPEED = 0.95f; private static final float SMOOTHING_CONSTANT
 * = (float) (0.016 / Math.log(SMOOTHING_SPEED)); private float mSmoothingTime;
 * private float mTouchX;
 * 
 * private WorkspaceOvershootInterpolator mScrollInterpolator;
 * 
 * private static final float BASELINE_FLING_VELOCITY = 2500.f; private static
 * final float FLING_VELOCITY_INFLUENCE = 0.4f;
 * 
 * private static class WorkspaceOvershootInterpolator implements Interpolator {
 * private static final float DEFAULT_TENSION = 1.3f; private float mTension;
 * 
 * public WorkspaceOvershootInterpolator() { mTension = DEFAULT_TENSION; }
 * 
 * public void setDistance(int distance) { mTension = distance > 0 ?
 * DEFAULT_TENSION / distance : DEFAULT_TENSION; }
 * 
 * public void disableSettle() { mTension = 0.f; }
 * 
 * public float getInterpolation(float t) { // _o(t) = t * t * ((tension + 1) *
 * t + tension) // o(t) = _o(t - 1) + 1 t -= 1.0f; return t * t * ((mTension +
 * 1) * t + mTension) + 1.0f; } }
 *//**
 * Used to inflate the Workspace from XML.
 * 
 * @param context
 *            The application's context.
 * @param attrs
 *            The attribtues set containing the Workspace's customization
 *            values.
 */
/*
 * public MySlide(Context context, AttributeSet attrs) { this(context, attrs,
 * 0); }
 *//**
 * Used to inflate the Workspace from XML.
 * 
 * @param context
 *            The application's context.
 * @param attrs
 *            The attribtues set containing the Workspace's customization
 *            values.
 * @param defStyle
 *            Unused.
 */
/*
 * public MySlide(Context context, AttributeSet attrs, int defStyle) {
 * super(context, attrs, defStyle); TypedArray a =
 * context.obtainStyledAttributes(attrs,R.styleable.DragableSpace, defStyle, 0);
 * mDefaultScreen = a.getInt(R.styleable.DragableSpace_default_screen, 1);
 * a.recycle();
 * 
 * setHapticFeedbackEnabled(false); initWorkspace(); }
 * 
 * 
 * public int getScreen_width() { return screen_width; }
 * 
 * public void setScreen_width(int screenWidth) { screen_width = screenWidth; }
 * 
 * public void setsListener(SlideListener sListener) { this.sListener =
 * sListener; }
 *//**
 * Initializes various states for this workspace.
 */
/*
 * private void initWorkspace() { Context context = getContext();
 * mScrollInterpolator = new WorkspaceOvershootInterpolator(); mScroller = new
 * Scroller(context, mScrollInterpolator); mCurrentScreen = mDefaultScreen;
 * final ViewConfiguration configuration = ViewConfiguration.get(getContext());
 * mTouchSlop = configuration.getScaledTouchSlop(); mMaximumVelocity =
 * configuration.getScaledMaximumFlingVelocity(); }
 *//**
 * Returns the index of the currently displayed screen.
 * 
 * @return The index of the currently displayed screen.
 */
/*
 * int getCurrentScreen() { return mCurrentScreen; }
 *//**
 * Sets the current screen.
 * 
 * @param currentScreen
 */
/*
 * void setToScreen(int currentScreen) { if (!mScroller.isFinished())
 * mScroller.abortAnimation();
 * 
 * mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount() - 1));
 * 
 * // scrollTo(mCurrentScreen * screen_width, 0);
 * mScroller.startScroll(mCurrentScreen * screen_width, 0, 0, 0, 10);
 * invalidate(); sListener.onComplete(currentScreen); }
 * 
 * 
 * 
 * 
 * @Override public void scrollTo(int x, int y) { super.scrollTo(x, y); mTouchX
 * = x; mSmoothingTime = System.nanoTime() / NANOTIME_DIV; }
 * 
 * @Override public void computeScroll() { if (mScroller.computeScrollOffset())
 * { mTouchX = mScrollX = mScroller.getCurrX(); mSmoothingTime =
 * System.nanoTime() / NANOTIME_DIV; scrollTo(mScrollX, 0); postInvalidate(); }
 * else if (mNextScreen != INVALID_SCREEN) { mCurrentScreen = Math.max(0,
 * Math.min(mNextScreen, getChildCount() - 1)); mNextScreen = INVALID_SCREEN;
 * clearChildrenCache(); } else if (mTouchState == TOUCH_STATE_SCROLLING) {
 * final float now = System.nanoTime() / NANOTIME_DIV; final float e = (float)
 * Math.exp((now - mSmoothingTime) / SMOOTHING_CONSTANT); final float dx =
 * mTouchX - mScrollX; mScrollX += dx * e; mSmoothingTime = now;
 * scrollTo(mScrollX, 0); // Keep generating points as long as we're more than
 * 1px away from the target if (dx > 1.f || dx < -1.f) {
 * 
 * postInvalidate(); } } }
 * 
 * @Override protected void dispatchDraw(Canvas canvas) { boolean restore =
 * false; int restoreCount = 0;
 * 
 * // ViewGroup.dispatchDraw() supports many features we don't need: // clip to
 * padding, layout animation, animation listener, disappearing // children, etc.
 * The following implementation attempts to fast-track // the drawing dispatch
 * by drawing only what we know needs to be drawn.
 * 
 * boolean fastDraw = mTouchState != TOUCH_STATE_SCROLLING && mNextScreen ==
 * INVALID_SCREEN; // If we are not scrolling or flinging, draw only the current
 * screen if (fastDraw) { drawChild(canvas, getChildAt(mCurrentScreen),
 * getDrawingTime()); } else { final long drawingTime = getDrawingTime(); final
 * float scrollPos = (float) mScrollX / screen_width; final int leftScreen =
 * (int) scrollPos; final int rightScreen = leftScreen + 1; if (leftScreen >= 0)
 * { drawChild(canvas, getChildAt(leftScreen), drawingTime); } if (scrollPos !=
 * leftScreen && rightScreen < getChildCount()) { drawChild(canvas,
 * getChildAt(rightScreen), drawingTime); } }
 * 
 * if (restore) { canvas.restoreToCount(restoreCount); } }
 * 
 * protected void onAttachedToWindow() { super.onAttachedToWindow();
 * computeScroll(); }
 * 
 * @Override protected void onMeasure(int widthMeasureSpec, int
 * heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 * 
 * final int width = MeasureSpec.getSize(widthMeasureSpec); final int widthMode
 * = MeasureSpec.getMode(widthMeasureSpec); if (widthMode !=
 * MeasureSpec.EXACTLY) { throw new
 * IllegalStateException("Workspace can only be used in EXACTLY mode."); }
 * 
 * final int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (heightMode
 * != MeasureSpec.EXACTLY) { throw new
 * IllegalStateException("Workspace can only be used in EXACTLY mode."); }
 * 
 * // The children are given the same width and height as the workspace final
 * int count = getChildCount(); for (int i = 0; i < count; i++) {
 * getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec); }
 * 
 * 
 * if (mFirstLayout) { setHorizontalScrollBarEnabled(false);
 * scrollTo(mCurrentScreen * width, 0); setHorizontalScrollBarEnabled(true);
 * mFirstLayout = false; } }
 * 
 * @Override protected void onLayout(boolean changed, int left, int top, int
 * right, int bottom) { int childLeft = 0;
 * 
 * final int count = getChildCount(); for (int i = 0; i < count; i++) { final
 * View child = getChildAt(i); if (child.getVisibility() != View.GONE) { final
 * int childWidth = child.getMeasuredWidth(); child.layout(childLeft, 0,
 * childLeft + childWidth, child.getMeasuredHeight()); childLeft += childWidth;
 * } } }
 * 
 * 
 * 
 * 
 * @Override public boolean dispatchUnhandledMove(View focused, int direction) {
 * if (direction == View.FOCUS_LEFT) { if (getCurrentScreen() > 0) {
 * snapToScreen(getCurrentScreen() - 1); return true; } } else if (direction ==
 * View.FOCUS_RIGHT) { if (getCurrentScreen() < getChildCount() - 1) {
 * snapToScreen(getCurrentScreen() + 1); return true; } } return
 * super.dispatchUnhandledMove(focused, direction); }
 * 
 * 
 * 
 * 
 * @Override public boolean onInterceptTouchEvent(MotionEvent ev) {
 * 
 * 
 * This method JUST determines whether we want to intercept the motion. If we
 * return true, onTouchEvent will be called and we do the actual scrolling
 * there.
 * 
 * 
 * 
 * Shortcut the most recurring case: the user is in the dragging state and he is
 * moving his finger. We want to intercept this motion.
 * 
 * final int action = ev.getAction(); if ((action == MotionEvent.ACTION_MOVE) &&
 * (mTouchState != TOUCH_STATE_REST)) { return true; }
 * 
 * if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain();
 * } mVelocityTracker.addMovement(ev);
 * 
 * switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_MOVE: {
 * 
 * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
 * whether the user has moved far enough from his original down touch.
 * 
 * 
 * 
 * Locally do absolute value. mLastMotionX is set to the y value of the down
 * event.
 * 
 * final int pointerIndex = ev.findPointerIndex(mActivePointerId); final float x
 * = ev.getX(pointerIndex); final float y = ev.getY(pointerIndex); final int
 * xDiff = (int) Math.abs(x - mLastMotionX); final int yDiff = (int) Math.abs(y
 * - mLastMotionY);
 * 
 * final int touchSlop = mTouchSlop; boolean xMoved = xDiff > touchSlop; boolean
 * yMoved = yDiff > touchSlop;
 * 
 * if (xMoved || yMoved) {
 * 
 * if (xMoved) { // Scroll if the user moved far enough along the X axis
 * mTouchState = TOUCH_STATE_SCROLLING; mLastMotionX = x; mTouchX = mScrollX;
 * mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
 * enableChildrenCache(mCurrentScreen - 1, mCurrentScreen + 1); }
 * 
 * } break; }
 * 
 * case MotionEvent.ACTION_DOWN: { final float x = ev.getX(); final float y =
 * ev.getY(); // Remember location of down touch mLastMotionX = x; mLastMotionY
 * = y; mActivePointerId = ev.getPointerId(0);
 * 
 * 
 * If being flinged and user touches the screen, initiate drag; otherwise don't.
 * mScroller.isFinished should be false when being flinged.
 * 
 * mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST :
 * TOUCH_STATE_SCROLLING; break; }
 * 
 * case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP:
 * 
 * // Release the drag clearChildrenCache(); mTouchState = TOUCH_STATE_REST;
 * mActivePointerId = INVALID_POINTER;
 * 
 * if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker
 * = null; }
 * 
 * break;
 * 
 * case MotionEvent.ACTION_POINTER_UP: onSecondaryPointerUp(ev); break; }
 * 
 * 
 * The only time we want to intercept motion events is if we are in the drag
 * mode.
 * 
 * return mTouchState != TOUCH_STATE_REST; }
 * 
 * private void onSecondaryPointerUp(MotionEvent ev) { final int pointerIndex =
 * (ev.getAction() & MotionEvent.ACTION_POINTER_ID_MASK) >>
 * MotionEvent.ACTION_POINTER_ID_SHIFT; final int pointerId =
 * ev.getPointerId(pointerIndex); if (pointerId == mActivePointerId) { // This
 * was our active pointer going up. Choose a new // active pointer and adjust
 * accordingly. // TODO: Make this decision more intelligent. final int
 * newPointerIndex = pointerIndex == 0 ? 1 : 0; mLastMotionX =
 * ev.getX(newPointerIndex); mLastMotionY = ev.getY(newPointerIndex);
 * mActivePointerId = ev.getPointerId(newPointerIndex); if (mVelocityTracker !=
 * null) { mVelocityTracker.clear(); } } }
 *//**
 * If one of our descendant views decides that it could be focused now, only
 * pass that along if it's on the current screen.
 * 
 * This happens when live folders requery, and if they're off screen, they end
 * up calling requestFocus, which pulls it on screen.
 */
/*
 * @Override public void focusableViewAvailable(View focused) { View current =
 * getChildAt(mCurrentScreen); View v = focused; while (true) { if (v ==
 * current) { super.focusableViewAvailable(focused); return; } if (v == this) {
 * return; } ViewParent parent = v.getParent(); if (parent instanceof View) { v
 * = (View)v.getParent(); } else { return; } } }
 * 
 * void enableChildrenCache(int fromScreen, int toScreen) { if (fromScreen >
 * toScreen) { final int temp = fromScreen; fromScreen = toScreen; toScreen =
 * temp; }
 * 
 * final int count = getChildCount();
 * 
 * fromScreen = Math.max(fromScreen, 0); toScreen = Math.min(toScreen, count -
 * 1);
 * 
 * setChildrenDrawnWithCacheEnabled(true); setChildrenDrawingCacheEnabled(true);
 * 
 * }
 * 
 * void clearChildrenCache() { setChildrenDrawnWithCacheEnabled(false); }
 * 
 * boolean isBouncing = true;
 * 
 * 
 * public void rightBouncing() {
 * 
 * int delta = 200; mScroller.startScroll(mScrollX, 0, delta, 0, Math.abs(delta)
 * * 2); invalidate();
 * 
 * }
 * 
 * public void leftBouncing() { int delta = -200;
 * mScroller.startScroll(mScrollX, 0, delta, 0, Math.abs(delta) * 2);
 * invalidate();
 * 
 * }
 * 
 * @Override public boolean onTouchEvent(MotionEvent ev) {
 * 
 * 
 * 
 * if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain();
 * } mVelocityTracker.addMovement(ev);
 * 
 * final int action = ev.getAction();
 * 
 * switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN:
 * 
 * If being flinged and user touches, stop the fling. isFinished will be false
 * if being flinged.
 * 
 * if (!mScroller.isFinished()) { mScroller.abortAnimation(); }
 * 
 * // Remember where the motion event started mLastMotionX = ev.getX();
 * mActivePointerId = ev.getPointerId(0); if (mTouchState ==
 * TOUCH_STATE_SCROLLING) { enableChildrenCache(mCurrentScreen - 1,
 * mCurrentScreen + 1); } break; case MotionEvent.ACTION_MOVE: if (mTouchState
 * == TOUCH_STATE_SCROLLING) { // Scroll to follow the motion event final int
 * pointerIndex = ev.findPointerIndex(mActivePointerId); final float x =
 * ev.getX(pointerIndex); final float deltaX = mLastMotionX - x; mLastMotionX =
 * x;
 * 
 * if (deltaX < 0) { if (mTouchX > 0) { mTouchX += Math.max(-mTouchX, deltaX);
 * mSmoothingTime = System.nanoTime() / NANOTIME_DIV; invalidate(); } if
 * (isBouncing && mCurrentScreen == 0) { leftBouncing(); isBouncing = false; } }
 * else if (deltaX > 0) { if (isBouncing && mCurrentScreen == getChildCount() -
 * 1) { rightBouncing(); isBouncing = false; } final float availableToScroll =
 * getChildAt(getChildCount() - 1).getRight() - mTouchX - screen_width; if
 * (availableToScroll > 0) { mTouchX += Math.min(availableToScroll, deltaX);
 * mSmoothingTime = System.nanoTime() / NANOTIME_DIV; invalidate(); } } else {
 * awakenScrollBars(); } } break; case MotionEvent.ACTION_UP: if (mTouchState ==
 * TOUCH_STATE_SCROLLING) { final VelocityTracker velocityTracker =
 * mVelocityTracker; velocityTracker.computeCurrentVelocity(1000,
 * mMaximumVelocity); final int velocityX = (int)
 * velocityTracker.getXVelocity();
 * 
 * final int screenWidth = screen_width; final int whichScreen = (mScrollX +
 * (screenWidth / 2)) / screenWidth; final float scrolledPos = (float) mScrollX
 * / screenWidth;
 * 
 * if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) { // Fling hard enough
 * to move left. // Don't fling across more than one screen at a time. final int
 * bound = scrolledPos < whichScreen ? mCurrentScreen - 1 : mCurrentScreen;
 * snapToScreen(Math.min(whichScreen, bound), velocityX, true); } else if
 * (velocityX < -SNAP_VELOCITY && mCurrentScreen < getChildCount() - 1) { //
 * Fling hard enough to move right // Don't fling across more than one screen at
 * a time. final int bound = scrolledPos > whichScreen ? mCurrentScreen + 1 :
 * mCurrentScreen; snapToScreen(Math.max(whichScreen, bound), velocityX, true);
 * } else { snapToScreen(whichScreen, 0, true); isBouncing = true; }
 * 
 * if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker
 * = null; } } mTouchState = TOUCH_STATE_REST; mActivePointerId =
 * INVALID_POINTER; break; case MotionEvent.ACTION_CANCEL: mTouchState =
 * TOUCH_STATE_REST; mActivePointerId = INVALID_POINTER; break; case
 * MotionEvent.ACTION_POINTER_UP: onSecondaryPointerUp(ev); break; }
 * 
 * return true; }
 * 
 * void snapToScreen(int whichScreen) { snapToScreen(whichScreen, 0, false); }
 * 
 * private void snapToScreen(int whichScreen, int velocity, boolean settle) {
 * //if (!mScroller.isFinished()) return;
 * 
 * whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
 * 
 * enableChildrenCache(mCurrentScreen, whichScreen);
 * 
 * mNextScreen = whichScreen;
 * 
 * 
 * View focusedChild = getFocusedChild(); if (focusedChild != null &&
 * whichScreen != mCurrentScreen && focusedChild == getChildAt(mCurrentScreen))
 * { focusedChild.clearFocus(); }
 * 
 * final int screenDelta = Math.max(1, Math.abs(whichScreen - mCurrentScreen));
 * final int newX = whichScreen * screen_width; final int delta = newX -
 * mScrollX; int duration = (screenDelta + 1) * 100;
 * 
 * if (!mScroller.isFinished()) { mScroller.abortAnimation(); }
 * 
 * if (settle) { mScrollInterpolator.setDistance(screenDelta); } else {
 * mScrollInterpolator.disableSettle(); }
 * 
 * velocity = Math.abs(velocity); if (velocity > 0) { duration += (duration /
 * (velocity / BASELINE_FLING_VELOCITY)) FLING_VELOCITY_INFLUENCE; } else {
 * duration += 100; }
 * 
 * awakenScrollBars(duration); mScroller.startScroll(mScrollX, 0, delta, 0,
 * duration); invalidate(); sListener.onComplete(whichScreen); }
 * 
 * 
 * 
 * @Override protected Parcelable onSaveInstanceState() { final SavedState state
 * = new SavedState(super.onSaveInstanceState()); state.currentScreen =
 * mCurrentScreen; return state; }
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * public static class SavedState extends BaseSavedState { int currentScreen =
 * -1;
 * 
 * SavedState(Parcelable superState) { super(superState); }
 * 
 * private SavedState(Parcel in) { super(in); currentScreen = in.readInt(); }
 * 
 * @Override public void writeToParcel(Parcel out, int flags) {
 * super.writeToParcel(out, flags); out.writeInt(currentScreen); }
 * 
 * public static final Parcelable.Creator<SavedState> CREATOR = new
 * Parcelable.Creator<SavedState>() { public SavedState createFromParcel(Parcel
 * in) { return new SavedState(in); }
 * 
 * public SavedState[] newArray(int size) { return new SavedState[size]; } }; }
 * 
 * }
 */